#include "database.hpp"
#include <algorithm>
using namespace std;

database da;

vector<string> adi_split_to_record(string fileName)
{
    vector<string> vs;
    ifstream f(fileName, ios::in);
    if (!f)
    {
        cout << "File can't be opened." << endl;
    }
    string s((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
    f.close();

    int pos = 0;
    if ((pos = s.find("<eoh>")) >= 0 || (pos = s.find("<EOH>")) >= 0)
    {
        s = s.substr(pos + 5, s.size() - pos - 5);
    }

    while ((pos = s.find("<eor>")) >= 0 || (pos = s.find("<EOR>")) >= 0)
    {
        vs.push_back(s.substr(0, pos));
        s = s.substr(pos + 5, s.size() - pos - 5);
    }
    return vs;
}

void adi_extract_strings(const string &s, vector<string> &v, size_t start)
{
    size_t pos = s.find('<', start);
    if (pos == string::npos)
    {
        return;
    }
    size_t end = s.find('<', pos + 1);
    if (end == string::npos)
    {
        end = s.size();
    }
    v.push_back(s.substr(pos + 1, end - pos - 1));
    adi_extract_strings(s, v, end);
}

vector<string> adi_split_to_field(string &s)
{
    vector<string> v;
    adi_extract_strings(s, v, 0);
    return v;
}

void toup(string &s)
{
    string str = s;
    transform(str.begin(), str.end(), str.begin(), ::toupper);
    s = str;
}

field string_to_field(string str)
{
    str.erase(remove(str.begin(), str.end(), '\n'), str.end());
    field f;
    int pos = str.find(':');
    string tmp = str.substr(0, pos);
    toup(tmp);
    f.name = tmp;
    int pos2 = str.find('>');
    tmp = str.substr(pos + 1, pos2 - pos - 1);
    f.len = stoi(tmp);
    tmp = str.substr(pos2 + 1);
    f.set_content(tmp);
    return f;
}

void importadi(string str)
{
    vector<record> vr;
    auto vs = adi_split_to_record(str); // vs向量中每个元素为record字符串
    for (int i = 0; i < vs.size(); i++) // record
    {
        // cout << vs[i] << endl;
        vector<string> vtmp = adi_split_to_field(vs[i]);
        vector<field> all_in_one;
        record R;
        for (int j = 0; j < vtmp.size(); j++) // 分离field
        {
            // cout << vtmp.size() << endl;
            field ftmp = string_to_field(vtmp[j]);
            // ftmp.output();
            all_in_one.push_back(ftmp);
        }
        R.import(all_in_one);
        vr.push_back(R);
    }
    da.import(vr);
}

vector<string> split(string s, string subs)
{
    int loc;
    string ss;
    vector<string> v;
    while (int(s.find(subs)) >= 0)
    {
        loc = int(s.find(subs));
        ss = s.substr(0, loc);
        v.push_back(ss);
        s = s.substr(loc + subs.size(), s.size() - loc - subs.size());
    }
    v.push_back(s);
    return v;
}

void importcsv(string fileName)
{
    ifstream f(fileName, ios::in);
    if (!f)
    {
        cout << "File can't be opened." << endl;
    }
    string line;
    getline(f, line);
    vector<string> fieldNames;
    fieldNames = split(line, ",");

    for (int i = 0; i < fieldNames.size(); i++)
    {
        toup(fieldNames[i]);
    }

    vector<record> vr;
    while (getline(f, line))
    {
        vector<field> vf;
        vector<string> stmp = split(line, ",");
        for (int i = 0; i < stmp.size(); i++)
        {
            field ftmp;
            ftmp.name = fieldNames[i];
            ftmp.len = stmp[i].size();
            ftmp.content = stmp[i];
            vf.push_back(ftmp);
        }
        record rec;
        rec.import(vf);
        vr.push_back(rec);
    }

    f.close();

    da.import(vr);
}

void import(string &filename)
{
    vector<record> vr;
    std::ifstream file(filename); // 打开文件
    vector<string> vs;            // 定义字符串向量

    if (file.is_open())
    { // 如果文件打开成功
        string line;
        while (std::getline(file, line))
        {                       // 逐行读取文件内容
            vs.push_back(line); // 将每行内容添加到字符串向量中
        }
        file.close(); // 关闭文件
    }
    else
        cout << "Failed to open file." << endl;

    for (int i = 0; i < vs.size(); i++) // record
    {
        // cout << vs[i] << endl;
        vector<string> vtmp = adi_split_to_field(vs[i]);
        vector<field> all_in_one;
        record R;
        for (int j = 0; j < vtmp.size(); j++) // 分离field
        {
            // cout << vtmp.size() << endl;
            field ftmp = string_to_field(vtmp[j]);
            // ftmp.output();
            all_in_one.push_back(ftmp);
        }
        R.import(all_in_one);
        vr.push_back(R);
    }
    da.import(vr);
}

void outputfile(string &str)
{
    string ext = str.substr(str.find_last_of(".") + 1);
    ofstream outfileadi(str, ios::out); // 打开输出文件
    if (!outfileadi.is_open())
    {
        cout << "Failed to open output file!" << endl;
    }
    streambuf *coutbuf = cout.rdbuf(); // 获取cout的缓冲区指针
    cout.rdbuf(outfileadi.rdbuf());
    if (ext == "adi")
        da.output();
    else if (ext == "csv")
        da.outputcsv();
    else if (ext == "txt")
        da.output();
    cout.rdbuf(coutbuf);
    outfileadi.close();
}

void search_call(database &Da, string _call)
{
    int cnt = 0;
    for (auto it = Da.D.begin(); it != Da.D.end(); it++)
    {
        if ((*it).cal.content == _call)
        {
            cnt++;
            (*it).output1();
        }
    }
    cout << cnt << " record(s) found" << endl;
}

void search_time(database &Da, string t1, string t2)
{
    int cnt = 0;
    for (auto it = Da.D.begin(); it != Da.D.end(); it++)
    {
        // cout << (*it).qso.content << " " << t2.substr(0, 8) << " " << t1.substr(0, 8) << " " << (*it).qso.content << endl;
        // cout << (*it).tim.content << " " << t2.substr(8) << " " << t1.substr(8) << " " << (*it).tim.content << endl;
        if ((*it).qso.content < t2.substr(0, 8) && t1.substr(0, 8) < (*it).qso.content)
        {
            (*it).output();
            cnt++;
        }
        else if ((*it).qso.content == t2.substr(0, 8) || t1.substr(0, 8) == (*it).qso.content)
        {
            if ((*it).qso.content <= t2.substr(0, 8) && t1.substr(0, 8) <= (*it).qso.content)
            {
                (*it).output();
                cnt++;
            }
        }
    }
    cout << cnt << " record(s) found" << endl;
}

void deladi(string str)
{
    vector<record> vr;
    auto vs = adi_split_to_record(str); // vs向量中每个元素为record字符串
    for (int i = 0; i < vs.size(); i++) // record
    {
        // cout << vs[i] << endl;
        vector<string> vtmp = adi_split_to_field(vs[i]);
        vector<field> all_in_one;
        record R;
        for (int j = 0; j < vtmp.size(); j++) // 分离field
        {
            // cout << vtmp.size() << endl;
            field ftmp = string_to_field(vtmp[j]);
            // ftmp.output();
            all_in_one.push_back(ftmp);
        }
        R.import(all_in_one);
        vr.push_back(R);
    }
    da.del(vr);
}

int main(int argc, char *argv[])
{

    string datafile = "data.adi";
    import(datafile);
    string filename, output_filename, call;
    for (int i = 1; i < argc; i++)
    {
        if (string(argv[i]) == "-i")
        {
            // importadi(datafile);
            filename = string(argv[i + 1]);
            string ext = filename.substr(filename.find_last_of(".") + 1);
            if (ext == "adi")
                importadi(filename);
            else if (ext == "csv")
                importcsv(filename);
            //da.output();
            outputfile(datafile);
        }
        else if (string(argv[i]) == "-o")
        {
            output_filename = string(argv[i + 1]);
            outputfile(output_filename);
            cout << "Data has been output to file: " << output_filename << endl;
        }
        else if (string(argv[i]) == "-s")
        {
            call = string(argv[i + 1]);
            search_call(da, call);
        }
        else if (string(argv[i]) == "-l")
        {
            string time1, time2;
            time1 = string(argv[i + 1]);
            time2 = string(argv[i + 2]);
            search_time(da, time1, time2);
            // cout << time1.substr(8) << " " << time1.substr(0, 8);
        }
        else if (string(argv[i]) == "-d")
        {
            string delete_filename = string(argv[i + 1]);
            deladi(delete_filename);
            outputfile(datafile);
        }
    }

    return 0;
}